﻿using System;
using System.Collections.Generic;

using OpenTK;
using OpenTK.Graphics;
using OpenTK.Graphics.OpenGL;

using GLSL;

using MosCraft.Utilities;

namespace MosCraft.Graphics
{
    public class SkyBox
    {
        private List<Vector3d> starsVectors = new List<Vector3d>();
        private World world;
        private Entity entity;
        private float cloudOffsetX;

        private float sunSize = 30F;
        private float moonSize = 20F;
        private double starSize = 150D;

        public SkyBox(World world, Entity entity)
        {
            this.world = world;
            this.entity = entity;
            this.cloudOffsetX = 0;
            this.generateStarMap();
        }

        public void render(float deltaTime)
        {
            GL.DepthMask(false);
            GL.Enable(EnableCap.Blend);
            GL.BlendFunc(BlendingFactorSrc.SrcAlpha, BlendingFactorDest.One);

            GL.PushMatrix();
            // relative to the player entity
            GL.Translate(entity.Position);
            GL.Rotate(0.0F, 0.0F, 0.0F, 1.0F);
            //rotate around the entity based on world time
            GL.Rotate(world.getCelestialAngle(deltaTime) * 360F, 1.0F, 0.0F, 0.0F);

            //Render the sun
            Texture.getTexture("sun.png").bind();
            GL.Begin(BeginMode.Quads);
            GL.TexCoord2(0.0D, 0.0D); GL.Vertex3(-sunSize, 100.0f, -sunSize);
            GL.TexCoord2(1.0D, 0.0D); GL.Vertex3(sunSize, 100.0f, -sunSize);
            GL.TexCoord2(1.0D, 1.0D); GL.Vertex3(sunSize, 100.0f, sunSize);
            GL.TexCoord2(0.0D, 1.0D); GL.Vertex3(-sunSize, 100.0f, sunSize);
            GL.End();

            //Render the moon
            Texture.getTexture("moon.png").bind();
            GL.Begin(BeginMode.Quads);
            GL.TexCoord2(1.0D, 1.0D); GL.Vertex3(-moonSize, -100.0f, moonSize);
            GL.TexCoord2(0.0D, 1.0D); GL.Vertex3(moonSize, -100.0f, moonSize);
            GL.TexCoord2(0.0D, 0.0D); GL.Vertex3(moonSize, -100.0f, -moonSize);
            GL.TexCoord2(1.0D, 0.0D); GL.Vertex3(-moonSize, -100.0f, -moonSize);
            GL.End();

            float brightness = world.getStarBrightness(deltaTime);
            //Only render the stars if its night
            if (brightness > 0.0F)
            {
                GL.Disable(EnableCap.Texture2D);
                GL.Begin(BeginMode.Quads);
                GL.Color4(1f, 1f, 1f, brightness);
                foreach (Vector3d vector in starsVectors)
                {
                    GL.Vertex3(vector);
                }
                GL.End();
                GL.Enable(EnableCap.Texture2D);
            }

            GL.Disable(EnableCap.Blend);
            GL.DepthMask(true);
            GL.PopMatrix();
        }

        private void generateStarMap()
        {
            FastRandom random = new FastRandom(10842L);

            for (int i = 0; i < 1500; i++)
            {
                double x = random.nextFloat() * 2.0F - 1.0F;
                double y = random.nextFloat() * 2.0F - 1.0F;
                double z = random.nextFloat() * 2.0F - 1.0F;
                double size = 0.25F + random.nextFloat() * 0.25F;
                double posSqrd = x * x + y * y + z * z;

                if (posSqrd >= 1.0D || posSqrd <= 0.01D)
                {
                    continue;
                }

                posSqrd = 1.0D / Math.Sqrt(posSqrd);

                x *= posSqrd;
                y *= posSqrd;
                z *= posSqrd;

                double d5 = x * starSize;
                double d6 = y * starSize;
                double d7 = z * starSize;

                double d8 = Math.Atan2(x, z);
                double d9 = Math.Sin(d8);
                double d10 = Math.Cos(d8);
                double d11 = Math.Atan2(Math.Sqrt(x * x + z * z), y);
                double d12 = Math.Sin(d11);
                double d13 = Math.Cos(d11);
                double d14 = random.nextDouble() * Math.PI * 2D;
                double d15 = Math.Sin(d14);
                double d16 = Math.Cos(d14);

                for (int j = 0; j < 4; j++)
                {
                    double d17 = 0.0D;
                    double d18 = (double)((j & 2) - 1) * size;
                    double d19 = (double)((j + 1 & 2) - 1) * size;
                    double d20 = d17;
                    double d21 = d18 * d16 - d19 * d15;
                    double d22 = d19 * d16 + d18 * d15;
                    double d23 = d22;
                    double d24 = d21 * d12 + d20 * d13;
                    double d25 = d20 * d12 - d21 * d13;
                    double d26 = d25 * d9 - d23 * d10;
                    double d27 = d24;
                    double d28 = d23 * d9 + d25 * d10;

                    starsVectors.Add(new Vector3d(d5 + d26, d6 + d27, d7 + d28));
                }
            }
        }

    }
}
